
package com.yunos.camera.qrcode;

import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Map;
import java.util.Set;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import com.way.camera.R;
import com.yunos.camera.ScanModule;
//import com.zijunlin.Zxing.Demo.camera.CameraManager;
//import com.zijunlin.Zxing.Demo.CaptureActivity;
//import com.zijunlin.Zxing.Demo.R;

public class DecodeHandler extends Handler {

    private static final String TAG = DecodeHandler.class.getSimpleName();
    public static final int RESULT_NONE = -1;
    public static final int RESULT_QR = 0;
    public static final int RESULT_BAR = 1;
    private final ScanModule scanModule;
    private final MultiFormatReader multiFormatReader;

    static final Set<BarcodeFormat> PRODUCT_FORMATS;
    static final Set<BarcodeFormat> INDUSTRIAL_FORMATS;
    private static final Set<BarcodeFormat> ONE_D_FORMATS;
    static final Set<BarcodeFormat> QR_CODE_FORMATS = EnumSet.of(BarcodeFormat.QR_CODE);
    static final Set<BarcodeFormat> DATA_MATRIX_FORMATS = EnumSet.of(BarcodeFormat.DATA_MATRIX);
    static final Set<BarcodeFormat> AZTEC_FORMATS = EnumSet.of(BarcodeFormat.AZTEC);
    static final Set<BarcodeFormat> PDF417_FORMATS = EnumSet.of(BarcodeFormat.PDF_417);
    static {
        PRODUCT_FORMATS = EnumSet.of(BarcodeFormat.UPC_A,
                BarcodeFormat.UPC_E,
                BarcodeFormat.EAN_13,
                BarcodeFormat.EAN_8,
                BarcodeFormat.RSS_14,
                BarcodeFormat.RSS_EXPANDED);
        INDUSTRIAL_FORMATS = EnumSet.of(BarcodeFormat.CODE_39,
                BarcodeFormat.CODE_93,
                BarcodeFormat.CODE_128,
                BarcodeFormat.ITF,
                BarcodeFormat.CODABAR);
        ONE_D_FORMATS = EnumSet.copyOf(PRODUCT_FORMATS);
        ONE_D_FORMATS.addAll(INDUSTRIAL_FORMATS);
    }
    
    private static boolean isRotate = true;

    DecodeHandler(ScanModule scanModule) {
        Map<DecodeHintType,Object> hints = new EnumMap<DecodeHintType, Object>(DecodeHintType.class);
        Set<BarcodeFormat> decodeFormats = EnumSet.noneOf(BarcodeFormat.class);
        decodeFormats.addAll(ONE_D_FORMATS);
        decodeFormats.addAll(QR_CODE_FORMATS);
        String characterSet = "utf-8";
        hints.put(DecodeHintType.CHARACTER_SET, characterSet);
        hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);
        multiFormatReader = new MultiFormatReader();
        multiFormatReader.setHints(hints);
        this.scanModule = scanModule;
    }

    @Override
    public void handleMessage(Message message) {
        switch (message.what) {
            case R.id.decode:
                // Log.d(TAG, "Got decode message");
                synchronized (this) {
                    decode((byte[]) message.obj, message.arg1, message.arg2);
                }
                break;
            case R.id.quit:
                Looper.myLooper().quit();
                break;
        }
    }

    /**
     * Decode the data within the viewfinder rectangle, and time how long it
     * took. For efficiency, reuse the same reader objects from one decode to
     * the next.
     * 
     * @param data The YUV preview frame.
     * @param width The width of the preview frame.
     * @param height The height of the preview frame.
     */
    private void decode(byte[] data, int width, int height) {
        long start = System.currentTimeMillis();
        //Log.d("dyb_scan", "" + data.length + ", width " + width + " height " + height);
        int rectleft = (width-height)/2;
        if (isRotate) {
            isRotate = false;
        } else {
            isRotate = true;
        }
        byte tmp[] = new byte[height*height];
        if (isRotate) {
            for (int row = 0; row < height; row++) {
                for (int col = 0; col < height; col++) {
                    tmp[col*height+row] = data[row*width+col+rectleft];
                }
            }
        } else {
            for (int row = 0; row < height; row++) {
                for (int col = 0; col < height; col++) {
                    tmp[row*height+col] = data[row*width+col+rectleft];
                }
            }
        }
        PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(tmp, height, height, 0, 0,
                height, height, false);
        tmp = null;
        Result rawResult = null;
        if (source != null) {
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
            try {
                rawResult = multiFormatReader.decodeWithState(bitmap);
            } catch (ReaderException re) {
                // continue
            } finally {
                multiFormatReader.reset();
            }
        }
        long cost = System.currentTimeMillis()-start;
        Log.d("dyb_scan", "decode time is " + cost);
        //long start = System.currentTimeMillis();
        // QRCodeResult rawResult = new QRCodeResult();
        //rawResult.resString = decode(data, rawResult.location, width, height);
        //long cost = System.currentTimeMillis()-start;
        //Log.d("dyb_scan", "decode time is " + cost);
        if (rawResult != null) {
            //Log.d("dyb_scan", "decode result is " + rawResult.resString);
            Message message = Message.obtain(scanModule.getHandler(), R.id.decode_succeeded,
                    rawResult);
            message.sendToTarget();
        } else {
            Message message = Message.obtain(scanModule.getHandler(), R.id.decode_failed,
                    rawResult);
            message.sendToTarget();
        }
    }
    public static native String decode(byte data[], int points[], int width, int height);

    static {
        System.loadLibrary("qrcode_jni");
    }
}
